package com.GPS_based_training.custom_components;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.View;

/**
 * Class that define the custom component SpeedArrow, which is a graphical arrow that 
 * say to the athlete if he has to speed up or slow down.
 * @author Andreas Scalas
 */
public class SpeedArrow extends View {
	
	private final float TRIANGLE_HEIGHT_RATIO = 2.5F; //The ratio between the height of the canvas and the height of the triangle
	private final float TRIANGLE_WIDTH_RATIO = 3.5F; //The ratio between the width of the canvas and the width of the triangle
	
	//What part of the height it has to be kept before the draw of the rectangle
	private final float RECTANGLE_RATIO = 1/4.0F;  

	private final int STROKE_WIDTH = 5; //The width of the lines
	
	private Paint paint; //The paint which is used to draw the view
	
	//The intensities of the view
	private int alphaIntensity;
	private final int redIntensity;
	private final int greenIntensity;
	private final int borderGreenColor;
	private final int borderRedColor;
	
	private boolean tooFast; //Reports if the arrow as to be downward
	private boolean tooSlow; //Reports if the arrow as to be upward
	
	/**
	 * @author Andreas Scalas
	 * The simplest constructor, based only on the context.
	 * @param context the context.
	 */
	public SpeedArrow(Context context) {
		
		this(context, null);
		
	}

	/**
	 * @author Andreas Scalas
	 * 
	 * A constructor based on the context and on a set of attributes.
	 * @param context the context.
	 * @param attrs the set of attributes.
	 */
	public SpeedArrow(Context context, AttributeSet attrs) {

		this(context, attrs, 0);
		
	}

	/**
	 * @author Andreas Scalas
	 * 
	 * A constructor based on the context, a set of attributes and a defined style.
	 * @param context the context.
	 * @param attrs the set of attributes.
	 * @param defStyleAttr the style.
	 */
	public SpeedArrow(Context context, AttributeSet attrs, int defStyleAttr) {

		super(context, attrs, defStyleAttr); 
		
		//Initializes the paint
		paint = new Paint();
        paint.setAntiAlias(true);
        
        //Initializes the flags
        tooFast = false;
        tooSlow = false;
        
        //Initializes the intensities.
        alphaIntensity = 0xFF;
        redIntensity = 0xCC;
        greenIntensity = 0xCC;
        borderGreenColor = 0xFF007700;
        borderRedColor = 0xFFD11700;
        
        
	}

	/**
	 * @author Andreas Scalas
	 * 
	 * Method that allow to re-define the measures of the view
	 * @param widthMeasureSpec actual width
	 * @param heightMeasureSpec actual height
	 */
	@Override
	public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){

		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		
		int measuredWidth, measuredHeight;
	    int widthSize = MeasureSpec.getSize(widthMeasureSpec);//Obtains actual width of the view
	    int heightSize = MeasureSpec.getSize(heightMeasureSpec);//Obtains actual height of the view
	    
	    measuredHeight = 2 * heightSize / 3;//Compute new height
	    measuredWidth =  widthSize / 2;//Compute new width
	    
		setMeasuredDimension(measuredWidth, measuredHeight);
		
	}
	
	/**
	 * @author Andreas Scalas
	 * 
	 * Method that defines the shape of the object based on the type of arrow (upward or downward).
	 * @param width the width of the canvas.
	 * @param height the height of the canvas.
	 * @param upward if the arrow is an upward arrow.
	 * @return the Path (shape) of the object.
	 */
	private Path defineArrowPath(int width, int height, boolean upward, boolean stable){
		
		Path path = new Path();
		float vertexA, vertexC; //Axis coordinates of the vertexes a and c of the triangular part of the shape.
		float vertexB; //Ordinate coordinate of the vertex b.
		float rectangleLeft, rectangleRight, rectangleUp, rectangleDown; //Coordinates of the rectangle.

		//Specifies that the internal part of the path is computed by an odd number of edge crossing.
		path.setFillType(Path.FillType.EVEN_ODD); 		
		
		if(stable){

			rectangleUp = height * RECTANGLE_RATIO; //Defines the position of rectangleUp
			rectangleDown = height - (height * RECTANGLE_RATIO); //Defines the position of rectangleDown
			
			//Defines the position the vertexes of the triangle part of the shape.
			vertexA = width / TRIANGLE_WIDTH_RATIO;
			vertexB = height / 2;
			vertexC = width / TRIANGLE_WIDTH_RATIO;
			
			//Create the shape of the double arrow (see the paints in the documentation) as a set of connected segments.
			path.moveTo(vertexA, height - STROKE_WIDTH);
			path.lineTo(STROKE_WIDTH, vertexB);
			path.lineTo(vertexC, STROKE_WIDTH);
			path.lineTo(vertexC, rectangleUp);
			path.lineTo(width - vertexC, rectangleUp);
			path.lineTo(width - vertexC, STROKE_WIDTH);
			path.lineTo(width - STROKE_WIDTH, vertexB);
			path.lineTo(width - vertexA, height - STROKE_WIDTH);
			path.lineTo(width - vertexA, rectangleDown);
			path.lineTo(vertexA, rectangleDown);
			path.lineTo(vertexA, height - STROKE_WIDTH);
			
		}else {
			
			rectangleLeft = width * RECTANGLE_RATIO; //Defines the position of rectangleLeft
			rectangleRight = width - (width * RECTANGLE_RATIO); //Defines the position of rectangleRight
			
			if(upward){ //If it is an upward arrow.
				
				//Defines the position the vertexes of the triangle part of the shape.
				vertexA = height / TRIANGLE_HEIGHT_RATIO;
				vertexB = width / 2;
				vertexC = height / TRIANGLE_HEIGHT_RATIO;
				
				//Create the shape of the arrow (see the paints in the documentation) as a set of connected segments.
				path.moveTo(STROKE_WIDTH, vertexA);
				path.lineTo(vertexB, STROKE_WIDTH);
				path.lineTo(width - STROKE_WIDTH, vertexC);
				path.lineTo(rectangleRight, vertexC);
				path.lineTo(rectangleRight, height - STROKE_WIDTH);
				path.lineTo(rectangleLeft, height - STROKE_WIDTH);
				path.lineTo(rectangleLeft, vertexA);
				path.lineTo(STROKE_WIDTH, vertexA);
				
			} else { //If it is a downward arrow.
				
				//Defines the position the vertexes of the triangle part of the shape.
				vertexA = height - height / TRIANGLE_HEIGHT_RATIO;
				vertexB = width / 2;
				vertexC = height - height / TRIANGLE_HEIGHT_RATIO;
				
				//Create the shape of the arrow (see the paints in the documentation) as a set of connected segments.
				path.moveTo(rectangleLeft, STROKE_WIDTH);
				path.lineTo(rectangleRight, STROKE_WIDTH);
				path.lineTo(rectangleRight, vertexC);
				path.lineTo(width - STROKE_WIDTH, vertexC);
				path.lineTo(vertexB, height - STROKE_WIDTH);
				path.lineTo(STROKE_WIDTH, vertexA);
				path.lineTo(rectangleLeft, vertexA);
				path.lineTo(rectangleLeft, STROKE_WIDTH);
				
			}
			
		}
		
		path.close(); //Close the Path.
		
		return path;
	}
	
	/**
	 * @author Andreas Scalas
	 * 
	 * Method that draw the canvas with the defined properties.
     * @param canvas the canvas on which draw object's appearance.
	 */
	@Override
	protected void onDraw(Canvas canvas){
				
		int height, width;
		
		//Obtains the dimensions of the canvas.
		height = canvas.getHeight();
		width = canvas.getWidth();

		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeWidth(STROKE_WIDTH);
		//The athlete can be only too fast or too slow at a time, if not, the arrow is not showed.
		if(this.tooSlow && !this.tooFast){
			
			//Defines the boundaries of the arrow.
			paint.setColor(borderGreenColor);
			canvas.drawPath(defineArrowPath(width, height, true, false), paint);
			
			paint.setStyle(Paint.Style.FILL);
			
			//Defines the color of the arrow
			paint.setARGB(alphaIntensity, 0, greenIntensity, 0);
			canvas.drawPath(defineArrowPath(width, height, true, false), paint);
			
		} else if (this.tooFast && !this.tooSlow){
		
			//Defines the boundaries of the arrow.
			paint.setColor(borderRedColor);
			canvas.drawPath(defineArrowPath(width, height, false, false), paint);
			
			paint.setStyle(Paint.Style.FILL);
			
			//Defines the color of the arrow
			paint.setARGB(alphaIntensity, redIntensity, 0, 0);
			canvas.drawPath(defineArrowPath(width, height, false, false), paint);
		
		} else {

			//Defines the boundaries of the arrow.
			paint.setARGB(0xFF, 0, 0, 0);
			paint.setStrokeWidth(STROKE_WIDTH);
			canvas.drawPath(defineArrowPath(width, height, false, true), paint);
			
		}

		
	}
	
	/**
	 * @author Andreas Scalas
	 * 
	 * The GET method for tooFast.
	 * @return if the athlete is too fast.
	 */
	public boolean isTooFast(){
		
		return this.tooFast;
		
	}
	
	/**
	 * @author Andreas Scalas
	 * 
	 * The SET method for tooFast.
	 * @param tooFast if the athlete is too fast. 
	 */
	public void setTooFast(boolean tooFast){
		
		this.tooFast = tooFast;
		
	}

	/**
	 * @author Andreas Scalas
	 * 
	 * The GET method for tooSlow.
	 * @return if the athlete is too slow.
	 */
	public boolean isTooSlow() {
		
		return tooSlow;
		
	}

	/**
	 * @author Andreas Scalas
	 * 
	 * The SET method for tooSlow.
	 * @param tooSlow if the athlete is too slow.
	 */
	public void setTooSlow(boolean tooSlow) {
		
		this.tooSlow = tooSlow;
		
	}

	/**
	 * @author Andreas Scalas
	 * 
	 * The GET method for alphaIntensity.
	 * @return alphaIntensity the intensity of the alpha component of the color
	 */
	public int getAlphaIntensity() {
		
		return alphaIntensity;
		
	}

	/**
	 * @author Andreas Scalas
	 * 
	 * The SET method for alphaIntensity.
	 * @return alphaIntensity the intensity of the alpha component of the color
	 */	
	public void setAlphaIntensity(int alphaIntensity) {
		
		this.alphaIntensity = alphaIntensity;
		
	}

}
